package org.example;

import com.almasb.fxgl.app.GameApplication;
import com.almasb.fxgl.app.GameSettings;
import com.almasb.fxgl.core.asset.AssetType;
import com.almasb.fxgl.core.math.FXGLMath;
import com.almasb.fxgl.dsl.FXGL;
import com.almasb.fxgl.entity.Entity;
import com.almasb.fxgl.entity.SpawnData;
import com.almasb.fxgl.physics.BoundingShape;
import com.almasb.fxgl.physics.CollisionHandler;
import com.almasb.fxgl.physics.HitBox;
import com.almasb.fxgl.texture.Texture;
import javafx.geometry.Point2D;
import javafx.geometry.Rectangle2D;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import org.example.components.GameTimerComponent;
import org.example.constans.HookStatusEnum;
import org.example.constans.TypeEnum;
import org.example.data.Level;
import org.example.data.LevelItem;
import org.example.data.ObjsItem;
import org.example.entity.GraspedEntity;
import org.example.entity.HookEntity;
import org.example.entity.StoneEntity;
import org.example.factory.GraspedFactory;
import org.jetbrains.annotations.NotNull;

import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.almasb.fxgl.dsl.FXGLForKtKt.image;
import static org.example.constans.Constants.*;

/**
 * Hello world!
 *
 */
public class GoldMinerApp extends GameApplication {
    private static ImageView OLD_MAN_IMAGE_VIEW = null;

    private static ImageView BG_IMAGE_VIEW = null;


    private static ImageView TOP_IMAGE_VIEW = null;

    /**
     * 钩子
     * @param args
     */
    private static ImageView HOOK_IMAGE_VIEW = null;

    private static HitBox HOOK_BOX = null;


    /**
     * 线
     */
    private Line line;

    private Entity lineEntity;

    /**
     * 是否正在抓取
     */
    private HookStatusEnum hookStatus = HookStatusEnum.IDLE;

    /**
     * 钩子实体
     */
    private HookEntity hookEntity;





    public static void main( String[] args ) {
        launch(args);
    }

    @Override
    protected void initSettings(GameSettings gameSettings) {
        gameSettings.setTitle("黄金矿工");
        gameSettings.setVersion("1.0");
        gameSettings.setWidth(1200);
        gameSettings.setHeight(800);
        gameSettings.setDeveloperMenuEnabled(true);
    }

    @Override
    protected void onPreInit() {
        OLD_MAN_IMAGE_VIEW = new ImageView(image("oldMan.png"));
        BG_IMAGE_VIEW = new ImageView(image("bk.png"));
        TOP_IMAGE_VIEW = new ImageView(image("top.png"));
        HOOK_IMAGE_VIEW = new ImageView(image("hook.png",38,22));

    }

    @Override
    protected void initGameVars(Map<String, Object> vars) {
        // 当前金钱
        vars.put("money", 0);

        // 当前关卡
        vars.put("level", 1);

    }

    @Override
    protected void initGame() {

        // 背景图
        setBg();

        // 加载静态资源
        FXGL.getAssetLoader().load(AssetType.SOUND, "lastart.wav");
        FXGL.getAssetLoader().load(AssetType.IMAGE,"shop.jpeg");

        FXGL.getGameWorld().addEntityFactory(new GraspedFactory());

        // 线
        line = new Line(0, 0, 0,  LINE_LENGTH);
        line.setStrokeWidth(3);

        HOOK_IMAGE_VIEW.setX( - (HOOK_IMAGE_VIEW.getImage().getWidth() / 2));
        HOOK_IMAGE_VIEW.setY(LINE_LENGTH);
        HOOK_BOX = new HitBox("hook", new Point2D(-HOOK_IMAGE_VIEW.getImage().getWidth() / 2, LINE_LENGTH),
                BoundingShape.box(HOOK_IMAGE_VIEW.getImage().getWidth(),HOOK_IMAGE_VIEW.getImage().getHeight()));
        lineEntity = FXGL.entityBuilder().zIndex(10)
                .at(TOP_IMAGE_VIEW.getFitWidth() / 2, TOP_IMAGE_VIEW.getFitHeight() - 20)
                .viewWithBBox(line)
                .type(TypeEnum.HOOK)
                .view(HOOK_IMAGE_VIEW)
                .bbox(HOOK_BOX)
                .collidable()
                .rotationOrigin(new Point2D(line.getStartX(), line.getStartY()))
                .buildAndAttach();

        hookEntity = new HookEntity();

        Level levelInfo = FXGL.getAssetLoader().loadJSON("data/level.json", Level.class).get();
        int currentLevel = FXGL.geti("level");

        Map<Integer, LevelItem> levelMap = levelInfo.levels().stream().collect(Collectors.toMap(LevelItem::level, Function.identity()));

        LevelItem levelItem = Optional.ofNullable(levelMap.get(currentLevel)).orElse(levelMap.get(levelMap.keySet().size() - 1));

        // 当前关卡数据
        FXGL.set("target", levelItem.target());

        Rectangle2D bounds = getRandomRectangle2D();

        for (ObjsItem obj : levelItem.objs()) {
            for (int i = 0; i < obj.num(); i++) {
                Point2D position = FXGLMath.randomPoint(bounds);
                FXGL.spawn(obj.name(), new SpawnData().put("pos",position)
                        .put("info",obj));
            }
        }


        // 计时
        FXGL.entityBuilder().with(new GameTimerComponent()).buildAndAttach();
    }

    @NotNull
    private static Rectangle2D getRandomRectangle2D() {
        Rectangle2D bounds = new Rectangle2D(0, TOP_IMAGE_VIEW.getFitHeight() + 50, FXGL.getAppWidth(), (FXGL.getAppHeight() - TOP_IMAGE_VIEW.getFitHeight() - 100));
        return bounds;
    }

    @Override
    protected void initInput() {
        FXGL.onKey(KeyCode.S, () -> {
            if(this.hookStatus == HookStatusEnum.IDLE) {
                // 如果钩子是空闲状态 改为抓取状态
                this.hookStatus = HookStatusEnum.GRAB;
                // 播放音效
                FXGL.play("lastart.wav");
            }

        });



    }

    @Override
    protected void initUI() {
        Text level = FXGL.addVarText("level", TOP_IMAGE_VIEW.getFitWidth() - 130, TOP_IMAGE_VIEW.getFitHeight() - 26);
        level.setFill(Color.DARKRED);
        level.fontProperty().unbind();
        level.setFont(Font.font(30));

        Text target =FXGL.getUIFactoryService()
                .newText(FXGL.getip("target").asString("$%d"));
        target.setLayoutX(180);
        target.setLayoutY(TOP_IMAGE_VIEW.getFitHeight() - 26);
        target.setFill(Color.INDIANRED);
        target.fontProperty().unbind();
        target.setFont(Font.font(30));
        FXGL.addUINode(target);

        Text money = FXGL.getUIFactoryService()
                .newText(FXGL.getip("money").asString("$%d"));
        money.setLayoutX(105);
        money.setLayoutY(45);
        money.setFill(Color.GREEN);
        money.fontProperty().unbind();
        money.setFont(Font.font(30));
        FXGL.addUINode(money);
    }

    @Override
    protected void onUpdate(double tpf) {
        // 钩子摆动
        if(hookStatus == HookStatusEnum.IDLE) {

            // 应用旋转到ImageView
            if(lineEntity.getRotation() >= HOOK_ROTATION_MAX) {
                hookEntity.setDir(-1);
            } else if (lineEntity.getRotation() <= HOOK_ROTATION_MIN){
                hookEntity.setDir(1);
            }

            lineEntity.setRotation(lineEntity.getRotation() + hookEntity.getSwingSpeed());

        } else if (hookStatus == HookStatusEnum.GRAB){
            Point2D point2D = getGrabXY(hookEntity.getGrabSpeed());
            line.setEndX(point2D.getX());
            line.setEndY(point2D.getY());

            HOOK_IMAGE_VIEW.setX(line.getEndX() - (HOOK_IMAGE_VIEW.getImage().getWidth() / 2));
            HOOK_IMAGE_VIEW.setY(line.getEndY());
            if(point2D.getX() <= 0 || (point2D.getX() >= FXGL.getAppWidth()) || point2D.getY() >= FXGL.getAppHeight()) {
                // 到了边界 停止抓取 回收
                System.out.println("到边界了");
                // 钩子上的物品清空
                hookEntity.setObj(null);
                hookStatus = HookStatusEnum.RECYCLE;
            }

            HOOK_BOX = new HitBox("hook",point2D,
                    BoundingShape.box(HOOK_IMAGE_VIEW.getImage().getWidth(),HOOK_IMAGE_VIEW.getImage().getHeight()));
            lineEntity.getBoundingBoxComponent().clearHitBoxes();
            lineEntity.getBoundingBoxComponent().addHitBox(HOOK_BOX);

        } else if (hookStatus == HookStatusEnum.RECYCLE) {
            // 回收钩子
            Point2D point2D = getRecycleXY(hookEntity.getRecycleSpeed());

            // 计算线的长度
            double lineLength = Math.sqrt(Math.pow(line.getEndX() - line.getStartX(), 2) + Math.pow(line.getEndY() - line.getStartY(), 2));

            if((lineLength ) <= LINE_LENGTH) {
                // 收完了 将碰撞箱重置
                HOOK_BOX = new HitBox("hook",new Point2D(point2D.getX() - HOOK_IMAGE_VIEW.getImage().getWidth() / 2,point2D.getY()),
                        BoundingShape.box(HOOK_IMAGE_VIEW.getImage().getWidth(),HOOK_IMAGE_VIEW.getImage().getHeight()));
                lineEntity.getBoundingBoxComponent().clearHitBoxes();
                lineEntity.getBoundingBoxComponent().addHitBox(HOOK_BOX);
                // 钩子状态重置
                hookStatus = HookStatusEnum.IDLE;

                // 移除实体
                if(hookEntity.getObj() != null) {
                    GraspedEntity graspedEntity = (GraspedEntity) (hookEntity.getObj());
                    graspedEntity.getEntity().removeFromWorld();
                    lineEntity.getViewComponent().removeChild(graspedEntity.getTexture());
                    // 物品清空
                    hookEntity.setObj(null);
                    //  加分数
                    FXGL.inc("money",graspedEntity.getEntity().getInt("money"));
                }




                return;
            }

            line.setEndX(point2D.getX());
            line.setEndY(point2D.getY());
            HOOK_IMAGE_VIEW.setX(line.getEndX() - (HOOK_IMAGE_VIEW.getImage().getWidth() / 2));
            HOOK_IMAGE_VIEW.setY(line.getEndY());


            if(hookEntity.getObj() != null) {
                // 抓着的实体
                Texture texture = ((GraspedEntity) hookEntity.getObj()).getTexture();
                texture.setX(point2D.getX() - texture.getFitWidth() / 2);
                texture.setY(point2D.getY());
            }
        }

    }

    @NotNull
    private Point2D getGrabXY(double speed) {
        double endY = line.getEndY();
        double endX = line.getEndX();
        // 计算角度
        double dx = endX - line.getStartX();
        double dy = endY - line.getStartY();
        double angle = Math.atan2(dy, dx);
        // 更新终点
        Point2D point2D = new Point2D(endX + Math.abs(speed * Math.cos(angle)), endY + Math.abs(speed * Math.sin(angle)));

        return point2D;
    }

    @NotNull
    private Point2D getRecycleXY(double speed) {
        double endY = line.getEndY();
        double endX = line.getEndX();
        // 计算角度
        double dx = endX - line.getStartX();
        double dy = endY - line.getStartY();
        double angle = Math.atan2(dy, dx);
        // 更新终点
        Point2D point2D = new Point2D(endX - Math.abs(speed * Math.cos(angle)), endY - Math.abs(speed * Math.sin(angle)));

        return point2D;
    }

    private void setBg() {
        // 头部
        TOP_IMAGE_VIEW.setFitWidth(1200);
        TOP_IMAGE_VIEW.setFitHeight(132.5);
        FXGL.entityBuilder().view(TOP_IMAGE_VIEW).buildAndAttach();

        BG_IMAGE_VIEW.setFitHeight(FXGL.getAppHeight() - TOP_IMAGE_VIEW.getFitHeight());
        BG_IMAGE_VIEW.setFitWidth(FXGL.getAppWidth());
        BG_IMAGE_VIEW.setY(TOP_IMAGE_VIEW.getFitHeight());

        FXGL.entityBuilder().view(BG_IMAGE_VIEW).buildAndAttach();



    }

    @Override
    protected void initPhysics() {
        FXGL.getPhysicsWorld().addCollisionHandler(new CollisionHandler(TypeEnum.HOOK,TypeEnum.STONE) {
            @Override
            protected void onCollisionBegin(Entity hook, Entity stone) {
                double weight = stone.getDouble("weight");
                int money = stone.getInt("money");
                StoneEntity obj = new StoneEntity(weight,money);
                obj.setEntity(stone);
                Texture texture = (Texture) stone.getViewComponent().getChildren().get(0);
                obj.setTexture(texture);
                lineEntity.getViewComponent().addChild(texture);
                hookEntity.setObj(obj);
                stone.setVisible(false);

                hookStatus = HookStatusEnum.RECYCLE;
            }
        });
    }
}
